package com.jsurf;

public class ResponseLayer {
	private int mWidth;
	private int mHeight;
	private int mStep;		// step size
	private int mFilter;
	
	public char[][] mLaplacian;	// laplacian sign storage
	public float[][] mResponses;	// response storage
	
	ResponseLayer(int width, int height, int step, int filter, IntegralImage integralImage) {
		mWidth = width; 
		mHeight = height;
		mStep = step;
		mFilter = filter;
		
		mLaplacian = new char[mWidth][mHeight];
		mResponses = new float[mWidth][mHeight];
		
		buildResponseLayer(integralImage);
	}
	
	//! Calculate DoH responses for supplied layer
	private void buildResponseLayer(IntegralImage img) {
		int b = (mFilter - 1) / 2 + 1;		// border for this filter
		int l = mFilter / 3; 				// lobe for this filter (filter size / 3)
		int w = mFilter; 					// filter size
		float inverse_area = 1f / (w * w); 	// normalisation factor
		float Dxx, Dyy, Dxy;

		for (int r, c, ar = 0; ar < mHeight; ++ar) {
			for (int ac = 0; ac < mWidth; ++ac) {
				// Get the image coordinates
				r = ar * mStep;
				c = ac * mStep;
				
				// Compute response components
				Dxx = SurfUtil.BoxIntegral(img, r - l + 1, c - b, 2 * l - 1, w)
				  	- SurfUtil.BoxIntegral(img, r - l + 1, c - l / 2, 2 * l - 1, l) * 3;
				Dyy = SurfUtil.BoxIntegral(img, r - b, c - l + 1, w, 2 * l - 1)
				  	- SurfUtil.BoxIntegral(img, r - l / 2, c - l + 1, l, 2 * l - 1) * 3;
				Dxy = + SurfUtil.BoxIntegral(img, r - l, c + 1, l, l)
				      + SurfUtil.BoxIntegral(img, r + 1, c - l, l, l)
				      - SurfUtil.BoxIntegral(img, r - l, c - l, l, l)
				      - SurfUtil.BoxIntegral(img, r + 1, c + 1, l, l);
				
				// Normalise the filter responses with respect to their size
				Dxx *= inverse_area;
				Dyy *= inverse_area;
				Dxy *= inverse_area;
				
				// Get the determinant of hessian response & laplacian sign
				mResponses[ac][ar] = (Dxx * Dyy - 0.81f * Dxy * Dxy);
				mLaplacian[ac][ar] = (char)(Dxx + Dyy >= 0 ? 1 : 0);
				
				SurfUtil.totalResponses += mResponses[ac][ar];
				SurfUtil.totalDxx += Dxx;
				SurfUtil.totalDyy += Dyy;
				SurfUtil.totalDxy += Dxy;
			}
		}
	}
	
	public float getResponse(int row, int col) {
		return mResponses[col][row];
	}
	
	public char getLaplacian(int row, int col) {
		return mLaplacian[col][row];
	}
	
	public int getWidth() {
		return mWidth;
	}
	
	public int getHeight() {
		return mHeight;
	}
	
	public int getFilter() {
		return mFilter;
	}
	
	public int getStep() {
		return mStep;
	}
	
	public float getResponse(int row, int col, ResponseLayer src) {
		int scale = getWidth() / src.getWidth();
		return getResponse(row * scale, col * scale);
	}
	
	public float getLaplacian(int row, int col, ResponseLayer src) {
		int scale = getWidth() / src.getWidth();
		return getLaplacian(row * scale, col * scale);
	}
}
